const request = require('request');
var multiparty = require('multiparty');
const fs = require('fs');
const { to } = require('await-to-js');
const { exec } = require('child_process');
const os = require('os');
var path = require('path');

const PYPath = path.join(os.homedir(), 'video-subtitle-extractor-gitee/backend');

async function chatGPT_d(prompt, cookie, opts) {
    opts = opts || {};
    return new Promise((resolve, reject) => {
        const body = {
            conversationId: '',
            bizId: opts.bizId || 'trial3.5',
            bizToken: opts.bizToken || '7E5E7D60-BED1-4891-ABC4-DD99E670CCC7',
            temperature: '0',
            ssoClientId: 'SSO1.0',
            apiKey: '',
            respMaxTokens: 3000,
            message: prompt,
            systemMessage: '',
        }
        if (opts.nologin) {
            delete body.ssoClientId;
        }
        if (opts.userId) {
            body.userId = opts.userId;
        }
        const paramList = []
        Object.keys(body).forEach((key) => {
            if (typeof body[key] === 'undefined')
                return

            paramList.push(`${key}=${body[key]}`)
        })
        console.log(paramList.join('&'))
        request({
            url: 'https://wq.jd.com/webstatic/srt-chat2',
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                cookie,
            },
            body: paramList.join('&'),
        }, (err, data, body) => {
            console.log(err, body);
            if (err) {
                reject(err);
            } else {
                try {
                    body = JSON.parse(body).data.choices[0].message.content;
                    // console.log(body);
                    resolve(body);
                } catch(e){
                    // console.log(e)
                    // reject(e);
                    resolve(body.trim());
                }
            }
        })
        // let result = '';
        // fetchSSE('http://chatgpt-relay.jd.com/chatgptrelay/chat', {
        //   method: 'POST',
        //   headers: {
        //     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        //     cookie: cookie,
        //   },
        //   body: paramList.join('&'),
        //   // signal: new AbortController().signal,
        //   onMessage: (data) => {
        //     console.log('onMessage:', data)
        //     try {
        //       let response = JSON.parse(data);
        //       if (response.data) {
        //         response = response.data;
        //         if (response === '[DONE]') {
        //           // result.text = result.text.trim()
        //           // res.end()
        //           resolve(result);
        //           return false
        //         } else {
        //           result += response.choices[0].delta.content;
        //         }
        //       } else {
        //         reject('data error');
        //       }
        //     }
        //     catch (err) {
        //       reject(err);
        //     }
        //   },
        // })
    });
}

// 根据名称获取类型
function getMimeType(filename) {
    return filename.split('.').pop();
}
const supportMime = ['txt', 'srt'];

// 读取数据
function getdata (opts) {
    opts = opts || {};
    // 优先读取全局变量
    if (global.SRTS) {
        let _t = JSON.parse(JSON.stringify(global.SRTS));
        // console.log(_t, opts);
        for (let i in opts) {
            _t.list = _t.list.filter((ceil) => (typeof ceil[i] == 'undefined' ? 0 : ceil[i]) == opts[i])
        }
        setTimeout(() => {
            // 事后也要重新读一下数据
            global.SRTS = JSON.parse(fs.readFileSync(process.cwd() + '/userfiles/srts.js', 'utf8'));
        }, 0)
        return _t;
    }
    try {
        let _t = JSON.parse(fs.readFileSync(process.cwd() + '/userfiles/srts.js', 'utf8'));
        global.SRTS = _t;
        for (let i in opts) {
            _t.list = _t.list.filter((ceil) => (ceil[i] == 'undefined' ? 0 : ceil[i]) == opts[i])
        }
        return _t;
    } catch (e) {
        return {
            autoindex: 0,
            count: 0,
            retry: 3,
            list: [],
        };
    }
}

// 保存数据
function savedata (data) {
    global.SRTS = data;
    return fs.writeFileSync(process.cwd()  + '/userfiles/srts.js', JSON.stringify(data));
}

// 读取数据
function readsrtFile (path) {
    const _t = fs.readFileSync(path, 'utf8').match(/(^|\n)\s*\d+\s*\n\s*[^\n]+\n[^\n]+(\n|$)/g);
    // 判断条数
    try {
        return Array.from(_t, (ceil) => {
            let _temp = ceil.split(/\n/);
            const _now = [];
            _temp.forEach((cceil) => {
                if (cceil.trim()) {
                    _now.push(cceil.trim());
                }
            });
            return _now;
        });
    }  catch (e) {
        return [];
    }
}

// 分页获取总体数据
function getlist(pagenum, pagesize, isvideo) {
    pagenum = pagenum || 1;
    pagesize = pagesize || 20;
    const data = getdata({
        isvideo: isvideo ? 1 : 0
    });
    data.list.sort((a, b) => {
        if (a.modifytime - b.modifytime > 0) {
            return -1;
        } else if (a.modifytime - b.modifytime < 0) {
            return 1;
        } else {
            return 0;
        }
    });
    return data.list.slice((pagenum - 1) * pagesize, pagenum * pagesize);
}

// 查询某一条详细数据
function getone(id) {
    const data = getdata();
    return data.list.find((ceil) => ceil.id == id);
}

// 更新某一个数据
async function updateone (id, info) {
    const data = getdata();
    const index = data.list.findIndex((ceil) => ceil.id == id);
    for (var i in info) {
        data.list[index][i] = info[i];
    }
    data.list[index].modifytime = new Date().getTime();
    savedata(data);
}

// 新增数据
function addone(filename, opts) {
    opts = opts || {};
    const data = getdata();
    data.autoindex++;
    data.count++;
    data.list.push({
        filename,
        createtime: new Date().getTime(),
        modifytime: new Date().getTime(),
        status: 0, // 0 是新上传，1是执行中，2是执行完成，3是执行异常，4是异常待重试
        retry: 0, // 重试次数
        id: data.autoindex,
        usetime: 0, // 执行耗时
        downtimes: 0, // 下载次数
        downtime: 0, // 最新下载时间
        lines: opts.lines || 0, // 条数
        type: opts.type || 0, // 0是 中翻译英，1是英翻译中
        isvideo: opts.isvideo || 0, // 是否是视频
    });
    savedata(data);
    return data.autoindex;
}

// 删除数据
async function deleteone(id) {
    const data = getdata();
    data.count--;
    const index = data.list.findIndex((ceil) => ceil.id == id);
    // 还需要删除文件
    const _d = data.list[index];
    fs.unlink(process.cwd() + "/userfiles/srtin/" + _d.id + (_d.isvideo ? '.mp4' : '.srt'), function () {});
    fs.unlink(process.cwd() + "/userfiles/srtout/" + _d.id + (_d.isvideo ? '.mp4' : '.srt'), function () {});
    
    data.list.splice(index, 1);
    savedata(data);
}

// 拉取列表
exports.getlist = function (req, res, next) {
    res.jsonp({
        ret: 0,
        data: getlist(req.query.index, req.query.pagesize, req.query.isvideo)
    });
};

// 删除
exports.deleteit = function (req, res, next) {
    if (!req.query.id) {
        res.json({ ret: 1 });
        return false;
    }
    deleteone(req.query.id);
    res.jsonp({ret: 0});
}

exports.videofile = function (req, res, next) {
    if (!req.query.id) {
        res.json({ ret: 1 });
        return false;
    }
    const videoPath = process.cwd() + "/userfiles/" +  (req.query.type == 1 ? "srtout" : "srtin") + "/" + req.query.id + ".mp4";
    res.sendFile(videoPath);
}

exports.downloadori = function (req, res, next) {
    if (!req.query.id) {
        res.json({ ret: 1 });
        return false;
    }
    const item = getone(req.query.id);
    res.download(process.cwd() + "/userfiles/srtin/" + req.query.id + "." + (item.isvideo ? 'mp4' : 'srt'), item.filename, function (dlerr) {
        if (dlerr) {
            console.log("下载出错", item.fileName, dlerr);
        } else {
            console.log("下载ok", item.fileName);
        }
    });
}

// 下载
exports.download = function (req, res, next) {
    if (!req.query.id) {
        res.json({ ret: 1 });
        return false;
    }
    const item = getone(req.query.id);
    res.download(process.cwd() + "/userfiles/srtout/" + req.query.id + "." + (item.isvideo ? 'mp4' : 'srt'), item.filename, function (dlerr) {
        if (dlerr) {
            console.log("下载出错", item.fileName, dlerr);
        } else {
            // 给个记录
            updateone(req.query.id, {
                downtimes: +item.downtimes + 1, // 下载次数
                downtime: new Date().getTime(), // 最新下载时间
            });
            console.log("下载ok", item.fileName);
        }
    });
}

// 上传
exports.upload = function (req, res, next) {
    var form = new multiparty.Form();
    form.uploadDir = process.cwd() + "/temp/";
    form.parse(req, function (err, fields, files) {
        if (!fields) {
            res.json({ ret: 1 });
            return;
        }
        var type = fields.type ? fields.type[0] : 0;
        var inputFile = files.more_upload ? files.more_upload[0] : files.file[0];
        var preSize = +(files.file[0].size / 1024).toFixed(2);
        var uploadedPath = inputFile.path;
        var mimeType = getMimeType(inputFile.originalFilename)

        if (!supportMime.includes(mimeType)) {
            fs.unlink(uploadedPath, function () { });
            res.json({
                ret: 3,
                message: `不支持的文件类型,目前支持：${supportMime.join('、')}`
            })
            return
        }

        // 读取文件，判断格式
        const _rows = readsrtFile(uploadedPath);
        if (_rows && _rows.length) {
            const id = addone(inputFile.originalFilename, {
                lines: _rows.length,
                type
            });
            // 移动文件
            fs.renameSync(uploadedPath, process.cwd() + "/userfiles/srtin/" + id + ".srt");
            // 可以的
            res.json({
                ret: 0,
                message: uploadedPath
            })
        } else {
            fs.unlink(uploadedPath, function () { });
            // 不可以
            res.json({
                ret: 3,
                message: '上传文件的无有效字幕格式'
            })
        }
    });
}

// 上传视频
exports.uploadvideo = function (req, res, next) {
    var form = new multiparty.Form();
    form.uploadDir = process.cwd() + "/temp/";
    form.parse(req, function (err, fields, files) {
        if (!fields) {
            res.json({ ret: 1 });
            return;
        }
        var type = fields.type ? fields.type[0] : 0;
        var inputFile = files.more_upload ? files.more_upload[0] : files.file[0];
        var uploadedPath = inputFile.path;
        var mimeType = getMimeType(inputFile.originalFilename)

        const vsupportMime = ['mp4'];
        if (!vsupportMime.includes(mimeType)) {
            fs.unlink(uploadedPath, function () { });
            res.json({
                ret: 3,
                message: `不支持的文件类型,目前支持：${vsupportMime.join('、')}`
            })
            return
        }

        // 读取文件，判断格式
        const id = addone(inputFile.originalFilename, {
            type,
            isvideo: 1
        });
        // 移动文件
        fs.renameSync(uploadedPath, process.cwd() + "/userfiles/srtin/" + id + ".mp4");

        // 还要拷贝一份
        fs.copyFileSync(process.cwd() + "/userfiles/srtin/" + id + ".mp4", path.join(PYPath, 'video/video_' + id + '.mp4'));

        // 可以的
        res.json({
            ret: 0,
            message: uploadedPath
        })
    });
}

function tomineSec(str) {
    return new Date('1970-1-1 ' + str.replace(/,/, ':')).getTime() + 28800000;
}

// 翻译
exports.translate = async function (req, res, next) {
    const id = req.query.id;
    if (!id) {
        return res.json({
            ret: 4,
            message: '参数错误'
        })
    }
    const item = getone(req.query.id);
    // 去执行
    const itemdata = readsrtFile(path.join(PYPath, 'video/video_' + id + '.srt'));
    // 拿到所有数据，对数据进行分割，100句台词，一次请求
    const itemlen = Math.ceil(itemdata.length / 100);
    var lists = [];
    for (let i = 0; i < itemlen; i++) {
        lists.push(itemdata.slice(i * 100, i * 100 + 100));
    }
    console.log(itemdata);
    var funcs = [];
    lists.forEach((ceil) => {
        funcs.push(chatGPT_d(`${item.type == 1 ? `以下是一个示例的 ChatGPT 提示，用于翻译英文电影台词为中文，并按照相同的格式输出：
请帮我翻译下面的英文电影台词为中文：` : `以下是一个示例的 ChatGPT 提示，用于翻译中文电影台词为英文，并按照相同的格式输出：
请帮我翻译下面的中文电影台词为英文：`}
${Array.from(ceil, (cceil) => cceil[0] + ': ' + cceil[2] + '\n').join('')}`, {}, {
            // bizId: 'srt',
            // bizToken: '42501234-8ffa-4404-a47c-5678b132f6d1',
            bizId: 'engineer',
            bizToken: '3d1c4349-3efc-4c9e-ad8d-7fd0c1a46094',
            nologin: true,
            userId: 'srt',
        }));
    });
    const [err, result] = await to(Promise.all(funcs));
    console.log(err, result);
    const _obj = {};
    let count = 0;
    result.forEach((ceil) => {
        const _t = ceil.match(/\d+\s*\:\s*[^\n]+(\n|$)/g);
        _t.forEach((cceil) => {
            const _z = cceil.match(/^(\d+)\s*\:\s*([^\n]+)\n?/);
            if (_z && !_obj[_z[1]]) {
                count++;
                _obj[_z[1]] = _z[2];
            }
        });
    });
    if (count != itemdata.length) {
        // 有异常
        console.log('数据无法匹配 =>', 'ChatGPT处理了' + count + '条', '样本实际有' + itemdata.length + '条');
        res.json({
            ret: 3,
            message: '数据无法匹配 => ' + ('ChatGPT处理了' + count + '条', '样本实际有' + itemdata.length + '条')
        })
    } else {
        itemdata.forEach((ceil) => {
            ceil.push(_obj[ceil[0]]);
        });
        // 写文件
        fs.writeFileSync(path.join(PYPath, 'video/video_en_' + id + '.srt'), Array.from(itemdata, (ceil) => ceil[0] + '\n' + ceil[1] + '\n' + ceil[3] + '\n\n').join('').replace(/\n+$/, ''));
        console.log('任务完成');
        res.json({
            ret: 0,
            data: Array.from(itemdata, (ceil) => {
                var _t = ceil[1].split('-->')
                return [tomineSec(_t[0].trim()) - 600, tomineSec(_t[1].trim()) + 400]
            })
        })
    }
}

// 滚动结果
async function run (item) {
    var starttime = new Date();
    // 先更新状态
    const data = getdata();
    const index = data.list.findIndex((ceil) => ceil.id == item.id);
    data.list[index].status = 1;
    savedata(data);

    // 去执行
    const itemdata = readsrtFile(process.cwd() + "/userfiles/srtin/" + item.id + "." + (data.list[index].isvideo ? 'mp4' : 'srt'));

    if (data.list[index].isvideo) {
        // 写入vid
        fs.writeFileSync(path.join(PYPath, 'vid.txt'), item.id + '')

        console.log('开始执行python');
        // 处理视频
        exec('cd ' + PYPath + ' && python ./main.py', (error, stdout, stderr) => {
            if (error && error != 'null') {
                console.error(`执行Python脚本时出错: ${error}`);
                updateone(item.id, {
                    status: +data.list[index].retry + 1 >= 4 ? 3 : 4,
                    retry: +data.list[index].retry + 1
                });
                return;
            }

            // 输出Python脚本的标准输出
            console.log(`Python脚本输出：${stdout}`);
            updateone(item.id, {
                status: 2,
                retry: +data.list[index].retry + 1,
                usetime: new Date() - starttime
            });
            // 删除文件
            fs.unlink(path.join(PYPath, 'output/video_' + item.id + '_no_sub.mp4'), function () {});
            fs.unlink(path.join(PYPath, 'video/video_' + item.id + '.mp4'), function () {});

            // 移动文件
            fs.renameSync(path.join(PYPath, 'output/video_have_sub_' + item.id + '.mp4'), process.cwd() + "/userfiles/srtout/" + item.id + ".mp4");
            fs.renameSync(path.join(PYPath, 'video/video_' + item.id + '.srt'), process.cwd() + "/userfiles/extinfo/srt/" + item.id + ".srt");
            fs.renameSync(path.join(PYPath, 'video/video_en_' + item.id + '.srt'), process.cwd() + "/userfiles/extinfo/srt/" + item.id + ".srt");
        });
    } else {
        // 拿到所有数据，对数据进行分割，100句台词，一次请求
        const itemlen = Math.ceil(itemdata.length / 100);
        var lists = [];
        for (let i = 0; i < itemlen; i++) {
            lists.push(itemdata.slice(i * 100, i * 100 + 100));
        }
        var funcs = [];
        lists.forEach((ceil) => {
            funcs.push(chatGPT_d(`${item.type == 1 ? `以下是一个示例的 ChatGPT 提示，用于翻译英文电影台词为中文，并按照相同的格式输出：
请帮我翻译下面的英文电影台词为中文：` : `以下是一个示例的 ChatGPT 提示，用于翻译中文电影台词为英文，并按照相同的格式输出：
请帮我翻译下面的中文电影台词为英文：`}
${Array.from(ceil, (cceil) => cceil[0] + ': ' + cceil[2] + '\n').join('')}`, {}, {
                // bizId: 'srt',
                // bizToken: '42501234-8ffa-4404-a47c-5678b132f6d1',
                bizId: 'engineer',
                bizToken: '3d1c4349-3efc-4c9e-ad8d-7fd0c1a46094',
                nologin: true,
                userId: 'srt',
            }));
        });
        const [err, result] = await to(Promise.all(funcs));
        console.log(err, result);
        const _obj = {};
        let count = 0;
        result.forEach((ceil) => {
            const _t = ceil.match(/\d+\s*\:\s*[^\n]+(\n|$)/g);
            _t.forEach((cceil) => {
                const _z = cceil.match(/^(\d+)\s*\:\s*([^\n]+)\n?/);
                if (_z && !_obj[_z[1]]) {
                    count++;
                    _obj[_z[1]] = _z[2];
                }
            });
        });
        if (count != itemdata.length) {
            // 有异常
            console.log('数据无法匹配 =>', 'ChatGPT处理了' + count + '条', '样本实际有' + itemdata.length + '条');
            // 重新数据
            updateone(item.id, {
                status: +data.list[index].retry + 1 >= 4 ? 3 : 4,
                retry: +data.list[index].retry + 1
            });
        } else {
            itemdata.forEach((ceil) => {
                ceil.push(_obj[ceil[0]]);
            });
            // 可以写文件了
            updateone(item.id, {
                status: 2,
                retry: +data.list[index].retry + 1,
                usetime: new Date() - starttime
            });
            // 写文件
            fs.writeFileSync(process.cwd() + '/userfiles/srtout/' + item.id + '.srt', Array.from(itemdata, (ceil) => ceil[0] + '\n' + ceil[1] + '\n' + ceil[3] + '\n\n').join('').replace(/\n+$/, ''));
            console.log(item.id + '：任务完成');
        }
    }
}

function getrun() {
    const data = getdata();
    // 判断是否有在执行的
    const runing = data.list.filter((ceil) => ceil.status == 1);
    const torun = data.list.filter((ceil) => ceil.status == 0 || ceil.status == 4);
    if (runing.length >= 4) {
        // 有正在执行中的
        console.log('有正在执行中的');
    } else 
    if (torun.length) {
        // 有可以执行的
        console.log('开始执行');
        run(torun[0]);
    } else {
        // 没有
        console.log('无可执行的');
    }
}
// 直接滚动吧，1分钟来一次
setInterval(() => {
    getrun();
}, 10000)
getrun();